﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32.SafeHandles; 
using System.Diagnostics;
using System.Runtime.InteropServices; 
using GenericHid;

namespace ibuddylib {

    /// <summary>
    /// Entry point for the buddy library, manages all buddies on the system
    /// </summary>
    /// <remarks>
    /// This class is a singleton, and should not be instantiated directly. Use
    /// the static property Global to obtain a reference to the manager instance.
    /// </remarks>
    public class BuddyManager {
        private const string BUDDY_USB_ID = "vid_1130&pid_0002&mi_01";

        private List<UsbBuddy> buddies = new List<UsbBuddy>();
        private DeviceManagement devices;
        private AnyBuddy anyBuddy = null;
        private VoidBuddy voidBuddy = null;

        private BuddyManager() {
            devices = new DeviceManagement();
            anyBuddy = new AnyBuddy(this);
            voidBuddy = new VoidBuddy();
            FindDevices();
        }

        private static BuddyManager instance = null;

        public static BuddyManager Global {
            get {
                if (instance == null) instance = new BuddyManager();
                return instance;
            }
        }

        public List<UsbBuddy> Buddies {
            get {
                return buddies;
            }
        }

        public IBuddy AnyBuddy {
            get {
                return anyBuddy;
            }
        }

        /// <summary>
        /// Return the first buddy in the collection, or a voidbuddy if there are none
        /// </summary>
        internal IBuddy FirstBuddy {
            get {
                if (buddies.Count > 0) return buddies[0];
                return voidBuddy;
            }
        }

        /// <summary>
        /// Search all connected USB devices and detect the i-Buddies
        /// </summary>
        public void FindDevices() {
            Guid hidGuid = new Guid();
            string[] hidDevices = new string[128]; // Always large enough... (?)

            Hid.HidD_GetHidGuid(ref hidGuid);
            if (devices.FindDeviceFromGuid(hidGuid, ref hidDevices)) {
                // Examine all hidDevices for the i-Buddy identification string
                // We need the second subdevice (nr. mi_01)

                foreach (string usbPath in hidDevices)
                    if (usbPath.IndexOf(BUDDY_USB_ID) > -1)
                        FoundBuddy(usbPath);
            }
        }

        /// <summary>
        /// Add a given USB device to the collection as a physical buddy, if it wasn't known yet
        /// </summary>
        /// <param name="usbPath">The USB device identifier</param>
        private void FoundBuddy(string usbPath) {
            foreach (UsbBuddy buddy in buddies)
                if (buddy.UsbPath == usbPath)
                    return; /* Already known */

            // Add a new one
            UsbBuddy newBuddy = CreateBuddy(usbPath);
            if (newBuddy != null) buddies.Add(newBuddy);
        }

        /// <summary>
        /// Open a connection to the USB device and create a new buddy object for it
        /// </summary>
        private UsbBuddy CreateBuddy(string usbPath) {
            // FIXME: Device notifications
            //  success = MyDeviceManagement.RegisterForDeviceNotifications( myDevicePathName, FrmMy.Handle, hidGuid, ref deviceNotificationHandle );

            SafeFileHandle writeHandle = FileIO.CreateFile(usbPath, FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0);
            if (writeHandle.IsInvalid) return null;

            return new UsbBuddy(usbPath, writeHandle);
        }
    }
}
